其他
Spring本质系列(2)-AOP
The following article is from 码农翻身 Author 刘欣
这些词就包括上一篇文章 - Spring 的本质系列(1) -- 依赖注入 中聊过的IoC 和 DI, 也包括今天要聊的AOP。
AOP(Aspect Oriented Programming)就是面向切面的编程, 为什么是面向切面, 而不是面向对象呢?
(码农翻身提示:如果你对设计模式不太熟, 可以跳过下文中的第2和第3节)
日志:对特定的操作输出日志来记录安全:在执行操作之前进行操作检查性能:要统计每个方法的执行时间事务:方法开始之前要开始事务, 结束后要提交或者回滚事务等等....
这些可以称为是非功能需求, 但他们是多个业务模块都需要的, 是跨越模块的, 把他们放到什么地方呢?
最简单的办法就是把这些通用模块的接口写好, 让程序员在实现业务模块的时候去调用就可以了,码农嘛,辛苦一下也没什么。
不仅仅这一个类需要这么干, 其他类都得这么干, 重复代码会非常的多。
有经验的程序员还好, 新手忘记写这样的非业务代码简直是必然的。
子类变的清爽, 只需要关注业务逻辑就可以了。调用也很简单,例如:BaseCommand cmd = ... 获得PlaceOrderCommand的实例...cmd.execute();
但是这样方式的巨大缺陷就是父类会定义一切: 要执行哪些非功能代码, 以什么顺序执行等等子类只能无条件接受,完全没有反抗余地。
如果有个子类, 根本不需要事务, 但是它也没有办法把事务代码去掉。
如果PaymentCommand 只需要打印日志,装饰一次就可以了:Command cmd = new LoggerDecorator( new PaymentCommand());cmd.execute();
可以使用任意数量装饰器,还可以以任意次序执行(严格意义上来说是不行的), 是不是很灵活?
最好把日志/安全/事务这样的代码和业务代码完全隔离开来,因为他们的关注点和业务代码的关注点完全不同 ,他们之间应该是正交的,他们之间的关系应该是这样的:
如果我们能让这些“切面“能和业务独立, 并且能够非常灵活的“织入”到业务方法中, 那就实现了面向切面编程(AOP)!
暂时停下脚步分析一下。
“对于com.coderising这个包中所有类的execute方法” , 用一个时髦的词来描述就是切入点(PointCut) , 它可以是一个方法或一组方法(可以通过通配符来支持,你懂的)
”在方法调用之前/之后 , 需要执行xxx“ , 用另外一个时髦的词来描述就是通知(Advice)码农翻身认为,PointCut,Advice 这些词实在是不直观, 其实Spring的作者们也是这么想的 : These terms are not Spring-specific… unfortunately, AOP terminology is not particularly intuitive; however, it would be even more confusing if Spring used its own terminology.
当然,想描述这些规则, xml依然是不二之选:
而AOP要求的恰恰就是在不改变业务类的源代码(其实大部分情况下你也拿不到)的情况下, 修改业务类的方法, 进行功能的增强,就像上面给所有的业务类增加事务支持。
为了突破这个限制,大家可以说是费尽心机, 现在基本是有这么几种技术:
(1) 在编译的时候, 根据AOP的配置信息,悄悄的把日志,安全,事务等“切面”代码 和业务类编译到一起去。
(2) 在运行期,业务类加载以后, 通过Java动态代理技术为业务类生产一个代理类, 把“切面”代码放到代理类中, Java 动态代理要求业务类需要实现接口才行。
(3) 在运行期, 业务类加载以后, 动态的使用字节码构建一个业务类的子类,将“切面”逻辑加入到子类当中去, CGLIB就是这么做的。
Spring采用的就是(1) +(2) 的方式,限于篇幅,这里不再展开各种技术了, 不管使用哪一种方式, 在运行时,真正干活的“业务类”其实已经不是原来单纯的业务类了, 它们被AOP了 !
● 深入浅出 CAS
如有收获,请帮忙转发,您的鼓励是作者最大的动力,谢谢!